package com.qhgrain.app.controller;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.xml.XMLSerializer;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.paas.base.modules.utils.lang.StringUtil;
import com.qhgrain.app.constant.UrlEnum;
import com.qhgrain.app.syncinfo.AppInfo;
import com.qhgrain.app.syncinfo.RoleInfo;
import com.qhgrain.app.syncinfo.SyncAppInfo;
import com.qhgrain.app.syncinfo.SyncInfo;
import com.qhgrain.app.syncinfo.SyncRoleInfo;
import com.qhgrain.app.syncinfo.SyncUnitInfo;
import com.qhgrain.app.syncinfo.SyncUserInfo;
import com.qhgrain.app.syncinfo.UnitInfo;
import com.qhgrain.app.syncinfo.UserInfo;
import com.qhgrain.app.util.ConfigUtil;
import com.qhgrain.gway.util.HttpUtil;


/**
 * 和4A同步，接收4A推送过来的数据，并解析
 *@description:
 *@company:怡和祥云
 *@version:1.0.0
 *@author weijianfei
 *@date: 2016年5月19日 下午5:47:54
 */
@RequestMapping("/sync4a/v1")
@Controller
public class Sync4AController {

	private static Logger LOG = LoggerFactory.getLogger(Sync4AController.class);
	
	
	private static String userOperURL = ConfigUtil.getProperties(UrlEnum.USER)+"/user";
	private static String unitOperURL = ConfigUtil.getProperties(UrlEnum.UNIT)+"/iunitservice";
	private static String appURL = ConfigUtil.getProperties(UrlEnum.APP)+"/application";
	private static String roleURL =  ConfigUtil.getProperties(UrlEnum.MENU_ROLE_PERMISSION)+"/role";
	
	private final static String OPERATION_INSERT = "INSERT";
	private final static String OPERATION_UPDATE = "MODIFY";
	private final static String OPERATION_DELETE = "DELETE";
	
	private final static String DataType_User="person";
	private final static String DataType_Unit="organizationalUnit";
	private final static String DataType_Group="group";
	private final static String DataType_App="application";
	
	/**
	 * 接收数据，并解析xml
	 * @param appMark
	 * @param utsNodeInfo
	 * @return
	 * @throws IOException 
	 * @throws UnsupportedEncodingException 
	 */
	@RequestMapping(value="syncDatas" ,method=RequestMethod.POST)
	@ResponseBody
	public String synchronizeDatas(String appMark, String utsNodeInfo,HttpServletResponse response,HttpServletRequest request) throws  IOException{	
		System.out.println("从4A传过来的数据："+utsNodeInfo);
		
		StringBuffer resData = new StringBuffer();
		try {
			
			resData.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><datas>");
			
			//用户
			List<SyncUserInfo> userList = new ArrayList<SyncUserInfo>();
			//组织 
			List<SyncUnitInfo> unitList = new ArrayList<SyncUnitInfo>();
			//角色
			List<SyncRoleInfo> roleList = new ArrayList<SyncRoleInfo>();
			//应用
			List<SyncAppInfo> appList = new ArrayList<SyncAppInfo>();
			
			//解析xml，收集数据
			parseXML(utsNodeInfo, userList, unitList, roleList,appList, resData);
		
			//操作类型，如果不是增删改类型的，剔除掉，并按照同步成功返回
			userList = checkNoDeal(userList,resData);
			unitList = checkNoDeal(unitList,resData);
			roleList = checkNoDeal(roleList,resData);
			appList = checkNoDeal(appList,resData);
			
			//检查app role数据完整性，缺少编码的，返回同步失败
			appList = checkAppData(appList, resData);
			roleList = checkRoleData(roleList, resData);
			
			//将收集到的数据同步到api
			sendUserToApi(userList, resData);
			sendUnitTopApi(unitList, resData);
			sendRoleToApi(roleList, resData);
			sendAppToApi(appList,resData);
			
		} catch (Exception e) {
			LOG.error("接收4A推送过来的数据，解析出现错误....syncData="+utsNodeInfo,e);
		}
		resData.append("</datas>");
		
		Map<String,String> map=new HashMap<String,String>();
		map.put("status", "success");
		map.put("message",resData.toString());
		
		String ss=JSONObject.toJSONString(map);
		
		System.out.println("返回给4A的结果:"+ ss);
		//LOG.error("4A同步返回结果:"+resData.toString());
		//return resData.toString();		
		response.getOutputStream().write(ss.getBytes("UTF-8"));
		return null;
	}
	/**
	 * 解析xml
	 * @param xmlInfo
	 */
	private void parseXML(String xmlInfo,List<SyncUserInfo> userList,
			List<SyncUnitInfo> unitList,List<SyncRoleInfo> roleList,
			List<SyncAppInfo> appList,StringBuffer resData)throws Exception{
		//解析xml
		
		SAXReader reader = new SAXReader();  
		//读取文件 转换成Document  
		Document document=null;
		document = reader.read(new ByteArrayInputStream(xmlInfo.getBytes()));		
		
		//获取根节点元素对象  
		Element root = document.getRootElement();//datas接到  			
		@SuppressWarnings("unchecked")
		List<Element> datas = root.elements();  //data节点
		//遍历属性节点  
        for(Element data:datas){  
           @SuppressWarnings("unchecked")
		List<Element> childs =data.elements();
           String type = "";
           String id = "";
           for(Element child:childs){
        	  if(child.getName().equals("type")){
        		  type=child.getText();
        	  }else if(child.getName().equals("id")){
        		  id = child.getTextTrim();
        	  }
           }
           
           try{
	           //同步人员
	           if(DataType_User.equals(type)){
			    	userList.add(convertToUser(data));
	           }else if(DataType_Unit.equals(type)){
	        	 //同步组织结构
	        	    unitList.add(convertToUnit(data));
	           }else if(DataType_Group.equals(type)){
	        	   //角色，对应应用群组
	        	   roleList.add(convertToRole(data));
	           }else if(DataType_App.equals(type)){
	        	   //应用
	        	   appList.add(convertToApp(data));
	           }else{
	        	   //未知类型，当作已同步成功处理
	        	   resData.append(responseData(id,true));
	           }
           }catch(Exception e){
        	   //收集转换失败的data
        	   LOG.error("4A同步...type="+type+",id="+id+",转换为对象是出错...",e);
        	   resData.append(responseData(id,false));
           }
        } 	
       
	}
	//使用(SyncUserInfo) xStream.fromXML(data.asXML())，则xml中对象的节点，
	//java对象中一定要有对应的，否则会报错,xml的来源是第三方，后期是否会更改，不确定
	//故不采取XStream.fromXML()这方法，而是先把xml转为json,json再转为java对象
	//注： 如果xml中节点没值，比如<a></a>那么转为java对象后会变为"[]"字符串
	private SyncUserInfo convertToUser(Element data){
		XMLSerializer xmlSeria = new XMLSerializer();
		return JSONObject.parseObject(xmlSeria.read(data.asXML()).toString(), SyncUserInfo.class);
	}
	private SyncUnitInfo convertToUnit(Element data){
		XMLSerializer xmlSeria = new XMLSerializer();
		return JSONObject.parseObject(xmlSeria.read(data.asXML()).toString(), SyncUnitInfo.class);
	}
	
	private SyncRoleInfo convertToRole(Element data){
		XMLSerializer xmlSeria = new XMLSerializer();
		return JSONObject.parseObject(xmlSeria.read(data.asXML()).toString(), SyncRoleInfo.class);
	}
	private SyncAppInfo convertToApp(Element data){
		XMLSerializer xmlSeria = new XMLSerializer();
		return JSONObject.parseObject(xmlSeria.read(data.asXML()).toString(), SyncAppInfo.class);
	}
	private String responseData(String id,boolean isSuccess){
		String s = "";
		if(!isSuccess){
			s = "<data><id>"+id+"</id><code>1</code><message>操作失败</message></data>";
		}else{
			s = "<data><id>"+id+"</id><code>0</code><message>操作成功</message></data>";
		}
		return s ;
	}
	/**
	 * 如果不是增删改类型的数据，则一律默认同步成功
	 * @param list
	 * @param resData
	 */
	private <T extends SyncInfo> List<T> checkNoDeal(List<T> list,StringBuffer resData){
		List<T> temp = new ArrayList<T>();
		if(list != null && list.size() > 0){
			for(SyncInfo syn : list){
				if(OPERATION_INSERT.equals(syn.getOperation()) || OPERATION_UPDATE.equals(syn.getOperation()) || OPERATION_DELETE.equals(syn.getOperation())){
					temp.add((T)syn);
				}else{
					resData.append(responseData(syn.getId(),true));
				}
			}
		}
		return temp;
	}
	
	/**
	 * 如果应用缺少编码，则一律返回同步失败
	 * @param list
	 * @param resData
	 * */
	private List<SyncAppInfo> checkAppData(List<SyncAppInfo> list,StringBuffer resData){
		List<SyncAppInfo> temp = new ArrayList<SyncAppInfo>();
		if(list != null && list.size()>0){
			for(SyncAppInfo syn : list){
				String serialNum = syn.getUtsNode().getSerialNumber();
				if(StringUtil.isNotBlank(serialNum) && !"[]".equals(serialNum)){
					temp.add(syn);
				}else {
					resData.append(responseData(syn.getId(),false));
				}
			}
		}
		
		return temp;
	}
	
	/**
	 * 角色缺少编码，则一律返回同步失败
	 * @param list
	 * @param resData
	 * */
	private List<SyncRoleInfo> checkRoleData(List<SyncRoleInfo> list, StringBuffer resData){
		List<SyncRoleInfo> temp = new ArrayList<SyncRoleInfo>();
		if(list != null && list.size()>0){
			for(SyncRoleInfo syn : list){
				String groupCode = syn.getUtsNode().getGroupCode();
				if(StringUtil.isNotBlank(groupCode) && !"[]".equals(groupCode)){
					temp.add(syn);
				} else {
					resData.append(responseData(syn.getId(),false));
				}
				
			}
		}
		
		return temp;
	}
	
	
	//同步用户数据到 api
	private void sendUserToApi(List<SyncUserInfo> userList,StringBuffer resData){
		try {
			Map<String,List<SyncUserInfo>> map = splitOperation(userList);
			//同步insert数据
			if(map.get(OPERATION_INSERT) != null){
				sendUserToApi(OPERATION_INSERT,map.get(OPERATION_INSERT),resData);
			}
			//同步update数据
			if(map.get(OPERATION_UPDATE) != null){
				sendUserToApi(OPERATION_UPDATE,map.get(OPERATION_UPDATE),resData);
			}
			//同步delete数据
			if(map.get(OPERATION_DELETE) != null){
				sendUserToApi(OPERATION_DELETE,map.get(OPERATION_DELETE),resData);
			}
			
		} catch (Exception e) {
			LOG.error("4A 同步用户数据发送到api失败...",e);
		}
	}
	private void sendUserToApi(String operation,List<SyncUserInfo> userList,StringBuffer resData){
		try {
			if(userList == null || userList.size() == 0) return;
			boolean isSyncSuccess = false;
			try {
				if(userList != null && userList.size() > 0){
					//将用户数据封装到JSONArray中
					JSONArray array = new JSONArray();
					JSONObject object = null;
					UserInfo user = null;
					for(SyncUserInfo info : userList){
						object = new JSONObject();
						user = info.getUtsNode();
						
						object.put("userId", info.getUuid());//id 
						object.put("loginName", user.getCn());//登录名称
						object.put("userName", user.getSn());//用户名称
					//	object.put("postId", user.getEmppositioncode());//岗位
						object.put("postName", user.getEmppositioncode());//岗位米ing错
					//	object.put("unitId", user.getOrgcode());//组织
						object.put("unitId", info.getNewParentUuid());
						object.put("unitName",info.getNewParentPath());
						//注： 如果xml中节点没值，比如<a></a>那么转为java对象后会变为"[]"字符串
						//所以，如果某个值等于"[]"的，则去掉
						object = check(object);
						
						array.add(object);
					}
					
					Map<String,Object> map = new HashMap<String,Object>();
					map.put("operationType", operation.toLowerCase());
					map.put("userList", array.toJSONString());
					String vo = HttpUtil.post(userOperURL+"/syncUsers", map);
					JSONObject voJson = JSONObject.parseObject(vo);
					if("1".equals(voJson.getString("state"))){
						isSyncSuccess = true;
					}else{
						isSyncSuccess = false;
						LOG.error("同步4A用户数据,api失败..operation="+operation+"....vo="+vo);
					}
					
					
				}
				
			} catch (Exception e) {
				LOG.error("同步4A用户数据，系统出错..operation="+operation,e);
				isSyncSuccess = false;
			}
			for(SyncUserInfo user : userList){
				resData.append(responseData(user.getId(),isSyncSuccess));
			}
		} catch (Exception e) {
		}
		
	}
	private void sendUnitTopApi(List<SyncUnitInfo> unitList,StringBuffer resData){
		try {
			Map<String,List<SyncUnitInfo>> map = splitOperation(unitList);
			//同步insert数据
			if(map.get(OPERATION_INSERT) != null){
				sendUnitToApi(OPERATION_INSERT,map.get(OPERATION_INSERT),resData);
			}
			//同步update数据
			if(map.get(OPERATION_UPDATE) != null){
				sendUnitToApi(OPERATION_UPDATE,map.get(OPERATION_UPDATE),resData);
			}
			//同步delete数据
			if(map.get(OPERATION_DELETE) != null){
				sendUnitToApi(OPERATION_DELETE,map.get(OPERATION_DELETE),resData);
			}
		} catch (Exception e) {
			LOG.error("4A 同步组织数据发送到api失败...",e);
		}
	}
	
	private void sendUnitToApi(String operation,List<SyncUnitInfo> unitList,StringBuffer resData){
		try {
			if(unitList == null || unitList.size() == 0) return;
			boolean isSyncSuccess = false;
			try {
				if(unitList != null && unitList.size() > 0){
					//将用户数据封装到JSONArray中
					JSONArray array = new JSONArray();
					JSONObject object = null;
					UnitInfo unit = null;
					for(SyncUnitInfo info : unitList){
						object = new JSONObject();
						unit = info.getUtsNode();
						//以下均需确认
						object.put("unitId", info.getUuid());
						object.put("unitName", unit.getOu());
						object.put("unitNo", unit.getDeptcode());
						//status,0停用，1启用
						//object.put("status"	, "N".equals(unit.getState())?"1":"0");
						object.put("status", "1");
						object.put("parentUnitid", info.getNewParentUuid());
						//unitType,0单位，1部门
						object.put("unitType", "否".equals(unit.getBusinesscategory())?1:0);//需判断
						
						//注： 如果xml中节点没值，比如<a></a>那么转为java对象后会变为"[]"字符串
						//所以，如果某个值等于"[]"的，则去掉
						object = check(object);
						
						array.add(object);
					}
					
					Map<String,Object> map = new HashMap<String,Object>();
					map.put("operationType", operation.toLowerCase());
					map.put("unitList", array.toJSONString());
					String vo = HttpUtil.post(unitOperURL+"/syncUnits", map);
					JSONObject voJson = JSONObject.parseObject(vo);
					if("1".equals(voJson.getString("state"))){
						isSyncSuccess = true;
					}else{
						isSyncSuccess = false;
						LOG.error("同步4A组织数据,api失败..operation="+operation+"....vo="+vo);
					}
					
					
				}
				
			} catch (Exception e) {
				LOG.error("同步4A组织数据，系统出错..operation="+operation,e);
				isSyncSuccess = false;
			}
			for(SyncUnitInfo unit : unitList){
				resData.append(responseData(unit.getId(),isSyncSuccess));
			}
		} catch (Exception e) {
		}
	}
	/**
	 * 角色数据同步到api
	 * @param roleList
	 * @param resData
	 */
	private void sendRoleToApi(List<SyncRoleInfo> roleList,StringBuffer resData){
		try {
			Map<String,List<SyncRoleInfo>> map = splitOperation(roleList);
			//同步insert数据
			if(map.get(OPERATION_INSERT) != null){
				sendRoleToApi(OPERATION_INSERT,map.get(OPERATION_INSERT),resData);
			}
			//同步update数据
			if(map.get(OPERATION_UPDATE) != null){
				sendRoleToApi(OPERATION_UPDATE,map.get(OPERATION_UPDATE),resData);
			}
			//同步delete数据
			if(map.get(OPERATION_DELETE) != null){
				sendRoleToApi(OPERATION_DELETE,map.get(OPERATION_DELETE),resData);
			}
		} catch (Exception e) {
			LOG.error("4A 同步组织数据发送到api失败...",e);
		}
	}
	
	private void sendRoleToApi(String operation,List<SyncRoleInfo> roleList,StringBuffer resData){
		try {
			if(roleList == null || roleList.size() == 0) return;
			boolean isSyncSuccess = false;
			try {
				if(roleList != null && roleList.size() > 0){
					//将用户数据封装到JSONArray中
					JSONArray array = new JSONArray();
					JSONObject object = null;
					RoleInfo role = null;
					for(SyncRoleInfo info : roleList){
						object = new JSONObject();
						role = info.getUtsNode();
						object.put("id", info.getUuid());
						object.put("name", role.getName());
						object.put("roleCode", role.getGroupCode());
						//如果1,2，则都归为1
						object.put("type", "2".equals(role.getGroupType())?"2":"1");//1应用角色，2业务角色
						object.put("status", "0");//0正常，1停用
						object.put("description", role.getDescription());
						
						//注： 如果xml中节点没值，比如<a></a>那么转为java对象后会变为"[]"字符串
						//所以，如果某个值等于"[]"的，则去掉
						object = check(object);
						
						array.add(object);
					}
					
					Map<String,Object> map = new HashMap<String,Object>();
					map.put("operationType", operation.toLowerCase());
					map.put("roleList", array.toJSONString());
					String vo = HttpUtil.post(roleURL+"/syncRoles", map);
					JSONObject voJson = JSONObject.parseObject(vo);
					if("1".equals(voJson.getString("state"))){
						isSyncSuccess = true;
					}else{
						isSyncSuccess = false;
						LOG.error("同步4A角色数据,api失败..operation="+operation+"....vo="+vo);
					}
					
					
				}
				
			} catch (Exception e) {
				LOG.error("同步4A组织数据，系统出错..operation="+operation,e);
				isSyncSuccess = false;
			}
			for(SyncRoleInfo role : roleList){
				resData.append(responseData(role.getId(),isSyncSuccess));
			}
		} catch (Exception e) {
		}
		
	}
	
	
	/**
	 * 应用数据同步到api
	 * @param appGroupList
	 * @param resData
	 */
	private void sendAppToApi(List<SyncAppInfo> appList,StringBuffer resData){
		try {
			Map<String,List<SyncAppInfo>> map = splitOperation(appList);
			//同步insert数据
			if(map.get(OPERATION_INSERT) != null){
				sendAppToApi(OPERATION_INSERT,map.get(OPERATION_INSERT),resData);
			}
			//同步update数据
			if(map.get(OPERATION_UPDATE) != null){
				sendAppToApi(OPERATION_UPDATE,map.get(OPERATION_UPDATE),resData);
			}
			//同步delete数据
			if(map.get(OPERATION_DELETE) != null){
				sendAppToApi(OPERATION_DELETE,map.get(OPERATION_DELETE),resData);
			}
		} catch (Exception e) {
			LOG.error("4A 同步组织数据发送到api失败...",e);
		}
	}
	
	private void sendAppToApi(String operation,List<SyncAppInfo> appList,StringBuffer resData){
		try {
			if(appList == null || appList.size() == 0) return;
			boolean isSyncSuccess = false;
			try {
				if(appList != null && appList.size() > 0){
					//将用户数据封装到JSONArray中
					JSONArray array = new JSONArray();
					JSONObject object = null;
					AppInfo app = null;
					for(SyncAppInfo info : appList){
						app = info.getUtsNode();
						object = new JSONObject();
						object.put("id", info.getUuid());
						object.put("appName",app.getName());
						//业务类型，传1-6,1表示数字政务云,2表示精确业务云,3表示智能粮库云,4表示智能辅助决策云，5表示电子商务云,6表示门户云
						//如果接受到的不是1-6，则都归到6中
						String type = "6";
						if(app.getBusinessType() != null && app.getBusinessType().matches("^[1-6]$")){
							type = app.getBusinessType();
						}
						object.put("businessType", type);
						object.put("iconClass", app.getIconClass());
						object.put("appCode", app.getSerialNumber());
						object.put("appUrl", app.getAppUrl());
						object.put("description", app.getDescription());
						//应用类型，0web，1手机
						object.put("appType","1".equals(app.getAppType())?"1":"0");
						//注： 如果xml中节点没值，比如<a></a>那么转为java对象后会变为"[]"字符串
						//所以，如果某个值等于"[]"的，则去掉
						object = check(object);
						
						array.add(object);
					}
					
					Map<String,Object> map = new HashMap<String,Object>();
					map.put("operationType", operation.toLowerCase());
					map.put("appList", array.toJSONString());
					String vo = HttpUtil.post(appURL+"/syncApps", map);
					JSONObject voJson = JSONObject.parseObject(vo);
					if("1".equals(voJson.getString("state"))){
						isSyncSuccess = true;
					}else{
						isSyncSuccess = false;
						LOG.error("同步4A应用数据,api失败..operation="+operation+"....vo="+vo);
					}
				}
				
			} catch (Exception e) {
				LOG.error("同步4A组织数据，系统出错..operation="+operation,e);
				isSyncSuccess = false;
			}
			for(SyncAppInfo app : appList){
				resData.append(responseData(app.getId(),isSyncSuccess));
			}
		} catch (Exception e) {
		}
		
	}
	
	/**
	 * 按操作类型进行分类
	 * <operation> : 操作类型
     * [ INSERT:添加，DELETE：删除，MODIFY：更新，MOVE : 移动 , PERMIT :授权，FORBID：取消授权]
	 * @param infoList
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private <T extends SyncInfo> Map<String,List<T>> splitOperation(List<T> infoList){
		Map<String,List<T>> map = new HashMap<String,List<T>>();
		List<T> tempList = null;
		for(SyncInfo si : infoList){
			if(map.get(si.getOperation()) == null){
				tempList = new ArrayList<T>();
				tempList.add((T)si);
				map.put(si.getOperation(), tempList);
			}else{
				map.get(si.getOperation()).add((T)si);
			}
		}
		return map;
	}

	/**
	 * 如果value="[]"则去掉该k/v
	 * @param json
	 * @return
	 */
   private JSONObject check(JSONObject json){
	   JSONObject j = new JSONObject();
	   for(Map.Entry<String, Object> m : json.entrySet()){
		   if(!"[]".equals(m.getValue())){
			   j.put(m.getKey(), m.getValue());
		   }else{
			   j.put(m.getKey(), "");
		   }
	   }
	   return j;
   }
	
}
